package com.iflytek.iot.common.utils;

import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * 针对java8的Optional进行增强
 * 代码风格为链式风格
 * <p>
 * Optional主要为了正常业务逻辑下规避空指针异常这种情况
 * <p>
 * 如果对象为null时可以由orElseGet()方法生成一个新对象来进行后续处理或者orElseThrow()方法抛异常
 * Optional通常是以ifPresent()方法结尾,如果执行到ifPresent()方法时对象还为null则无后续操作
 * 所以使用场景一般是在 [ 只考虑正常使用场景,忽略对象不为null的情况 ]
 * <p>
 * 但实际工作中,经常会有场景需要对null做不同的业务处理,
 * Optional并未提供此方法,且很多方法未提供返回值或者直接返回对象而非Optional对象,无法全程保持链式风格,
 * 所以封装了OptionalPlus以满足自己需求,并与Optional风格、命名等保持一致
 * <p>
 * 因为Optional是final类,所以无法直接继承,直接将原有代码拷贝过来改改也不太好,
 * 没想到更好的办法,只能先这样写着了
 * <p>
 * <p>
 * 与Optional不一样的地方:
 * 0.ofNullable(Optional<T> t)
 * 1.getOptional()   返回optional对象
 * 2.ifPresent()     存在则执行,多了返回值
 * 3.ifNotPresent()  为null则执行,与ifPresent()相反
 *
 * @author zurun
 * @date 2018/7/27 21:05:35
 * @see Optional
 */
public final class OptionalPlus<T> {

    private final Optional<T> optional;


    private OptionalPlus(Optional<T> optional) {
        this.optional = Objects.requireNonNull(optional);
    }

    public static <T> OptionalPlus<T> empty() {
        return new OptionalPlus<>(Optional.empty());
    }

    public static <T> OptionalPlus<T> of(T t) {
        return new OptionalPlus<>(Optional.of(t));
    }

    public static <T> OptionalPlus<T> ofNullable(T t) {
        return t == null ? empty() : of(t);
    }

    public static <T> OptionalPlus<T> ofNullable(Optional<T> t) {
        return t == null ? empty() : new OptionalPlus<>(t);
    }

    /**
     * 获取optional对象,只保证optional不为null
     *
     * @return
     */
    public Optional<T> getOptional() {
        if (optional == null) {
            throw new NoSuchElementException("No value present");
        }
        return optional;
    }

    public T get() {
        return getOptional().get();
    }

    public boolean isPresent() {
        return optional.isPresent();
    }

    /**
     * 如果不为null,执行回调,并返回this
     *
     * @param consumer
     * @return
     */
    public OptionalPlus<T> ifPresent(Consumer<? super T> consumer) {
        optional.ifPresent(consumer);
        return this;
    }

    public OptionalPlus<T> filter(Predicate<? super T> predicate) {
        return optional.filter(predicate).isPresent() ? this : empty();
    }

    public <U> OptionalPlus<U> map(Function<? super T, ? extends U> mapper) {
        return OptionalPlus.ofNullable(optional.map(mapper));
    }

    public T orElse(T other) {
        return optional.orElse(other);
    }

    public T orElseGet(Supplier<? extends T> other) {
        return optional.orElseGet(other);
    }

    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        return optional.orElseThrow(exceptionSupplier);
    }

    /**
     * 如果对象为null,执行回调,并返回this
     *
     * @param noArgsFunction
     * @return
     */
    public OptionalPlus<T> ifNotPresent(NoArgsFunction noArgsFunction) {
        if (!isPresent()) {
            noArgsFunction.todo();
        }
        return this;
    }


    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (!(obj instanceof OptionalPlus)) {
            return false;
        }

        OptionalPlus<?> other = (OptionalPlus<?>) obj;
        return Objects.equals(optional, other.getOptional());
    }

    @Override
    public int hashCode() {
        return Objects.hashCode(optional);
    }

    @Override
    public String toString() {
        return optional != null
                ? optional.toString()
                : "Optional.empty";
    }


}